
var doll = (function (_doll) {

    //handles collision with raycasting and prepares a scene for rendering
    //a world contains the scene
    _doll.world = function(options) {
        //options
        var t = this;
        this.scene = null;
        this.camera = null;
        this.obstacles = [];//things raycasted against for collision
        this.objects = [];//total objects in the world
        this.users = [];//array of users currently connected to the world
        this.sims = [];//things that require simulation steps

        this.set_options = function(opts) {
            for (o in opts) {
                var val = opts[o];
                if(val === undefined) {
                    console.warn('doll.world: undefined value ' + val + ' passed as option.');
                    continue;
                }
                
                if(o in t) {
                    var curVal = t[o];
                    if(curVal instanceof THREE.Color) {
                        curVal.set(val);
                    } else if(curVal instanceof THREE.Vector3 && val instanceof THREE.Vector3) {
                        curVal.copy(val);
                    } else {
                        t[o] = val;
                    }
                }
            }
        };

        this.set_options(options);

        //connect a user to this world...
        this.connect = function (u) {
            t.users[t.users.length] = u;
            u.world = t;
            t.scene.add(u.mesh);
        };

        //disconnect a user from this world...
        this.disconnect = function (u) {
            var i = t.users.indexOf(u);
            t.users.splice(i, 1);
            t.scene.remove(u.mesh);
        };


        //add some game object to the world
        this.add = function(o) {
            t.obstacles[t.obstacles.length] = o.mesh;
            t.scene.add(o.mesh);
            t.objects[t.objects.length] = o;
        }

        //add a mesh to the scene; debug mostly
        this.add_mesh = function(mesh) {
            t.obstacles[t.obstacles.length] = mesh;
            t.scene.add(mesh);
        }

        //add some function to simulate
        this.add_simulation = function(sim) {
            t.sims[t.sims.length] = sim;
        };
        
        //run all this world's simulations
        this.simulate = function(step) {
            for(var i=0; i<t.sims.length; i++) {
                t.sims[i](step);
            }
        };

        //call one per frame
        this.update = function(delta) {
            t.update_objects(delta);
            t.update_users(delta);
            camera.update(delta);
            //clear obstacle list
            //t.obstacles.length = 0;
        }

        this.post_anim_objects = []
        //called after all the animations are done
        this.post_animation = function(delta) {
            for(var i=0; i<t.objects.length; i++) {
                t.post_anim_objects[i].post_animation(delta);
            }            
        }

        //called at the end of every frame
        this.finalize_objects = [];
        this.finalize = function(delta) {
            for(var i=0; i<t.objects.length; i++) {
                t.finalize_objects[i].finalize(delta);
            }            
        }

        //send network information to other users
        //call as often as possible
        this.update_network = function() {
        }

        //update world objects rooms, physics, etc.
        this.update_objects = function(delta) {
            for(var i=0; i<t.objects.length; i++) {
                t.objects[i].update(delta);
            }
        }

        //update connected users
        this.update_users = function(delta) {
            for(var i=0; i<t.users.length; i++) {
                t.users[i].update(delta);
            }
        }

    };

    //proc is a namespace for procedural generated content
    _doll.proc = _doll.proc || {};

    //a moon surface for the demo I am currently working on
    //uses a cube map on a sphere to simulate the content of a planet
    _doll.proc.moon = function(options) {
        //options
        var t = this;
        this.obstacles = null;//things raycasted against for collision
        //passed to the world during collision test
        this.geo = null;
        this.mesh = null;//the surface of the moon is one huge mesh
        this.object = null;
        this.wiremesh = null;
        this.wiremat = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
        this.mat = [];//different materials used
        this.size = 200;

        this.set_options = function(opts) {
            for (o in opts) {
                var val = opts[o];
                if(val === undefined) {
                    console.warn('doll.proc.moon: undefined value ' + val + ' passed as option.');
                    continue;
                }
                
                if(o in t) {
                    var curVal = t[o];
                    if(curVal instanceof THREE.Color) {
                        curVal.set(val);
                    } else if(curVal instanceof THREE.Vector3 && val instanceof THREE.Vector3) {
                        curVal.copy(val);
                    } else {
                        t[o] = val;
                    }
                }
            }
        };

        this.set_options(options);

        //build the surface
        this.build_surface = function() {
            t.mat[0] = new THREE.MeshNormalMaterial();
            t.geo = new THREE.SphereGeometry(t.size,t.size/10,t.size/10);
            t.mesh = new THREE.Mesh(t.geo, t.mat[0]);
            t.wiremesh = new THREE.Mesh(t.geo, t.wiremat);

            t.object = new THREE.Object3D();
            t.object.add(t.mesh);
            t.object.add(t.wiremesh);
        };

        this.wireframe = false;
        this.toggle_wireframe = function() {
            if(!t.wireframe) {
                t.wiremesh.position.copy(t.mesh.position);
                _doll.scene.add(t.wiremesh);
                t.wireframe = true;
            } else {
                _doll.scene.remove(t.wiremesh);
                t.wireframe = false;
            }
        }

        //grass, dirt, water
        this.build_terrain = function () {

        };

        //trees flowers
        this.build_foliage = function () {
        
        };

        //add data for animal life
        this.build_creatures = function () {

        };

        //called once per frame
        this.update = function(delta) {
            if(t.wireframe) {
                t.wiremesh.position.copy(t.mesh.position);
            }
        }
        
        //call to step forward
        this.simulate = function(step) {
            t.simulate_ecosystem(step);
            t.simulate_creatures(step);
        }

        //simulate plant life
        this.simulate_ecosystem = function (step) {
            
        };

        //simulate lives of creatures (breeding, migration etc.)
        this.simulate_creatures = function (step) {
            
        };

    };

    return _doll;
}(doll || {}));

